package com.jlp.source.aspect;

import com.jlp.source.anno.DataSourceSign;
import com.jlp.source.config.DataSourceContextHolder;
import com.jlp.source.enums.ContextConst;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;

/**
 * @author lingpeng.jiang
 * @create 2022-01-09 15:03
 * @Description //TODO
 **/
@Aspect
@Order(-1)  //在开启事务之前切入
@Component
public class DynamicDataSourceAspect {

    /**
     * 方法执行之前切换为当前类或者方法上注解指定的数据源
     * @param point
     */
    @Before("execution(* com.jlp.source.service..*.*(..))")
    public void before(JoinPoint point) {
        try {
            // 获取类上@DataSourceSign注解
            DataSourceSign annotationOfClass =
                    point.getTarget().getClass().getAnnotation(DataSourceSign.class);

            String methodName = point.getSignature().getName();

            Class[] parameterTypes = ((MethodSignature) point.getSignature()).getParameterTypes();

            Method method = point.getTarget().getClass().getMethod(methodName, parameterTypes);
            // 获取方法上@DataSourceSign注解
            DataSourceSign methodAnnotation =
                    method.getAnnotation(DataSourceSign.class);

            methodAnnotation = Objects.isNull(methodAnnotation) ? annotationOfClass : methodAnnotation;

            ContextConst.DataSourceType dataSourceType =
                    Objects.nonNull(methodAnnotation) ?
                            methodAnnotation.value() : ContextConst.DataSourceType.MYSQL;
            DataSourceContextHolder.setDataSource(dataSourceType.name());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    /**
     * 方法执行结束后清除当前线程上下文的数据源信息，防止内存溢出
     * @param point
     */
    @After("execution(* com.jlp.source.service..*.*(..))")
    public void after(JoinPoint point) {
        DataSourceContextHolder.clearDataSource();
    }
}
